﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.Adapters;
using System.Web.UI.HtmlControls;
using System.Web.UI;
using SlidingButtons.Attributes;
using System.Web.UI.WebControls;

namespace SlidingButtons
{
  public class ResourceBuilder : ControlAdapter
  {
    // Return a strongly-typed reference
    public new Button Control
    {
      get
      {
        return (Button)base.Control;
      }
    }

    protected override void OnPreRender(EventArgs e)
    {
      base.OnPreRender(e);

      //only register the css references if the developer specified a css class
      if(!String.IsNullOrEmpty(Control.CssClass))
        RegisterCssReferences();
    }

    /// <summary>
    /// Registers the css references with the page
    /// </summary>
    protected void RegisterCssReferences()
    {
      //add the link to the page header instead of inside the body, which is not xhtml compliant
      HtmlHead header = this.Page.Header;

      if (header == null) throw new NotSupportedException("This page is missing a HtmlHead control which is required for the CSS stylesheet link that is being added. Please add <head runat=\"server\" />.");

      foreach (String styleSheet in this.CssReferences)
      {
        bool addIt = true;  // looking for this stylesheet already in the header
        foreach (Control c in header.Controls)
        {
          HtmlLink l = c as HtmlLink;
          if (l != null && styleSheet.Equals(l.Href, StringComparison.OrdinalIgnoreCase))
          {
            addIt = false;
            break;
          }
        }

        if (addIt)
        {
          HtmlLink link = new HtmlLink();
          link.Href = styleSheet;
          link.Attributes.Add("type", "text/css");
          link.Attributes.Add("rel", "stylesheet");
          header.Controls.Add(link);

          // ASP.NET AJAX doesn't currently send a new head element down during an async postback,
          // so we do the same thing on the client by registering the appropriate script for after
          // the update. A HiddenField is used to prevent multiple registrations.
          ScriptManager scriptManager = ScriptManager.GetCurrent(this.Page);

          if (scriptManager == null) throw new InvalidOperationException("A ScriptManager is required on the page to use the adapter");

          if (scriptManager.IsInAsyncPostBack &&
                        (null == this.Page.Request.Form["__AdapterCssLoaded"]))
          {
            ScriptManager.RegisterClientScriptBlock(this.Control, this.Control.GetType(), "RegisterCssReferences",
                "var head = document.getElementsByTagName('HEAD')[0];" +
                "if (head) {" +
                    "var linkElement = document.createElement('link');" +
                    "linkElement.type = 'text/css';" +
                    "linkElement.rel = 'stylesheet';" +
                    "linkElement.href = '" + styleSheet + "';" +
                    "head.appendChild(linkElement);" +
                "}"
                , true);
            ScriptManager.RegisterHiddenField(this.Control, "__AdapterCssLoaded", "");
          }
        }
      }
    }

    #region CssReferences

    private List<String> m_CssReferences = null;

    /// <summary>
    /// The list of css files used by this adapter
    /// </summary>
    protected List<String> CssReferences
    {
      get
      {
        //if the list has already been pulled, just return it
        if (m_CssReferences != null)
          return m_CssReferences;


        //otherwise, go through each required resource, and add it.
        m_CssReferences = new List<String>();

        foreach (CssResourceAttribute attr in this.GetType().GetCustomAttributes(typeof(CssResourceAttribute), true))
        {
          if(!String.IsNullOrEmpty(this.Control.CssClass) && attr.ResourcePath.Contains(this.Control.CssClass))
            m_CssReferences.Add(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), attr.ResourcePath));
        }

        return m_CssReferences;
      }
    }

    #endregion
  }
}
